/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.icee.myth.log;

import com.icee.myth.log.message.FileCYGameLogMessage;
import com.icee.myth.log.message.GameLogMessage;
import com.icee.myth.utils.Consts;
import com.icee.myth.utils.LinkedTransferQueue;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.FieldPosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author lidonglin
 */
public class FileLogCYThreadHandle implements Runnable{
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private SimpleDateFormat sdfSimp = new SimpleDateFormat("yyyy-MM-dd");
    
    private final LinkedTransferQueue<GameLogMessage> _loginQueue;
    private final LinkedTransferQueue<GameLogMessage> _registerQueue;
    private final LinkedTransferQueue<GameLogMessage> _rechargeQueue;
    private final LinkedTransferQueue<GameLogMessage> _roleQueue;
    private final LinkedTransferQueue<GameLogMessage> _onlineQueue;
    private final LinkedTransferQueue<GameLogMessage> _onlineTimeQueue;
    private final LinkedTransferQueue<GameLogMessage> _behaviorQueue;
    private final LinkedTransferQueue<GameLogMessage> _userQueue;
    private final LinkedTransferQueue<GameLogMessage> _commodityBuyQueue;
    private final LinkedTransferQueue<GameLogMessage> _commodityCostQueue;
    private final LinkedTransferQueue<GameLogMessage> _diamondQueue;
    private final LinkedTransferQueue<GameLogMessage> _taskQueue;
    private final LinkedTransferQueue<GameLogMessage> _downloadQueue;
    private final LinkedTransferQueue<GameLogMessage> _cardQueue;
    private final LinkedTransferQueue<GameLogMessage> _instanceQueueu;
    private final LinkedTransferQueue<GameLogMessage> _evolutionQueue;
    private final LinkedTransferQueue<GameLogMessage> _activateQueue;

    private BufferedWriter _loginBw;
    private BufferedWriter _registerBw;
    private BufferedWriter _rechargeBw;
    private BufferedWriter _roleBw;
    private BufferedWriter _onlineBw;
    private BufferedWriter _onlineTimeBw;
    private BufferedWriter _behaviorBw;
    private BufferedWriter _userBw;
    private BufferedWriter _commodityBuyBw;
    private BufferedWriter _commodityCostBw;
    private BufferedWriter _diamondBw;
    private BufferedWriter _taskBw;
    private BufferedWriter _downloadBw;
    private BufferedWriter _cardBw;
    private BufferedWriter _instanceBw;
    private BufferedWriter _evolutionBw;
    private BufferedWriter _activateBw;

    private final String rootPath;
    private final String pathName;
    private final int flushInterval;
    private final int bufferSize;

    private long realPrevTime;
    private long realPrevFiveMinutesTime;
    private long realCurrTime;

    public boolean shutdown = false;

    public FileLogCYThreadHandle(String rootPath, String pathName, int flush_interval, int bufferSize){
        this.rootPath = rootPath;
        this.pathName = pathName;
        this.flushInterval = flush_interval;
        this.bufferSize = bufferSize;

        _loginQueue = new LinkedTransferQueue<GameLogMessage>();
        _registerQueue = new LinkedTransferQueue<GameLogMessage>();
        _rechargeQueue = new LinkedTransferQueue<GameLogMessage>();
        _roleQueue = new LinkedTransferQueue<GameLogMessage>();
        _onlineQueue = new LinkedTransferQueue<GameLogMessage>();
        _onlineTimeQueue = new LinkedTransferQueue<GameLogMessage>();
        _behaviorQueue = new LinkedTransferQueue<GameLogMessage>();
        _userQueue = new LinkedTransferQueue<GameLogMessage>();
        _commodityBuyQueue = new LinkedTransferQueue<GameLogMessage>();
        _commodityCostQueue = new LinkedTransferQueue<GameLogMessage>();
        _diamondQueue = new LinkedTransferQueue<GameLogMessage>();
        _taskQueue = new LinkedTransferQueue<GameLogMessage>();
        _downloadQueue = new LinkedTransferQueue<GameLogMessage>();
        _cardQueue = new LinkedTransferQueue<GameLogMessage>();
        _instanceQueueu = new LinkedTransferQueue<GameLogMessage>();
        _evolutionQueue = new LinkedTransferQueue<GameLogMessage>();
        _activateQueue = new LinkedTransferQueue<GameLogMessage>();
    }

    public void log(GameLogMessage message) {
        switch (message.type) {
            case GAMELOGTYPE_CY_LOGIN:
                _loginQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_REGISTER:
                _registerQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_BEHAVIOR:
                _behaviorQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_RECHARGE:
                _rechargeQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_ROLE:
                _roleQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_ONLINE:
                _onlineQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_ONLINE_TIME:
                _onlineTimeQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_USER:
                _userQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_COMMODITY_BUY:
                _commodityBuyQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_COMMODITY_COST:
                _commodityCostQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_DIAMOND:
                _diamondQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_TASK:
                _taskQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_DOWNLOAD:
                _downloadQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_CARD:
                _cardQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_INSTANCE:
                _instanceQueueu.offer(message);
                break;
            case GAMELOGTYPE_CY_EVOLUTION:
                _evolutionQueue.offer(message);
                break;
            case GAMELOGTYPE_CY_ACTIVATE:
                _activateQueue.offer(message);
                break;
        }
    }

     private String now() {
        return sdf.format(new Date());
    }

     private String nowSimp() {
         return sdfSimp.format(new Date());
     }

    private void createDirectoryIfNotExist(String path) {
        File dir = new File(path);
        if (!dir.exists()) {
            dir.mkdirs();
        }
    }

    private void setFileRefDaily() {
        try {
            createDirectoryIfNotExist(rootPath + pathName + "/cylog");

            StringBuffer dateStringBuffer = new SimpleDateFormat("yyyy-MM-dd").format(new Date(realCurrTime), new StringBuffer(), new FieldPosition(0));
            String dateString = dateStringBuffer.toString();

            if (_roleBw != null){
                _roleBw.close();
            }
            _roleBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_ROLE_MC_LOG + "." + dateString, true), bufferSize);

            if (_onlineTimeBw != null){
                _onlineTimeBw.close();
            }
            _onlineTimeBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_ONLINE_TIME_MC_LOG + "."  + dateString, true), bufferSize);

            if (_userBw != null){
                _userBw.close();
            }
            _userBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_USER_MC_LOG + "."  + dateString, true), bufferSize);

            if (_taskBw != null){
                _taskBw.close();
            }
            _taskBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_TASK_MC_LOG + "."  + dateString, true), bufferSize);

            if (_commodityBuyBw != null){
                _commodityBuyBw.close();
            }
            _commodityBuyBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_COMMODITY_BUY_MC_LOG + "."  + dateString, true), bufferSize);

            if (_commodityCostBw != null){
                _commodityCostBw.close();
            }
            _commodityCostBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_COMMODITY_COST_MC_LOG + "." + dateString, true), bufferSize);

            if (_downloadBw != null){
                _downloadBw.close();
            }
            _downloadBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_DOWNLOAD_MC_LOG + "."  + dateString, true), bufferSize);

            if (_cardBw != null){
                _cardBw.close();
            }
            _cardBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_CARD_LOG + "."  + dateString, true), bufferSize);

            if (_instanceBw != null){
                _instanceBw.close();
            }
            _instanceBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_INSTANCE_LOG + "."  + dateString, true), bufferSize);

            if (_evolutionBw != null){
                _evolutionBw.close();
            }
            _evolutionBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_EVOLUTION_LOG + "." + dateString, true), bufferSize);

            if (_activateBw != null){
                _activateBw.close();
            }
            _activateBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_ACTIVATE_LOG + "."  + dateString, true), bufferSize);
            
        } catch (IOException ex) {
            Logger.getLogger(FileLogThreadHandle.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void setFileRefFiveMinuetes() {
        try {
            createDirectoryIfNotExist(rootPath + pathName + "/cylog");

            StringBuffer dateStringBuffer = new SimpleDateFormat("yyyy-MM-dd.HHmm").format(new Date(realCurrTime), new StringBuffer(), new FieldPosition(0));
            String dateString = dateStringBuffer.toString();

            if (_loginBw != null){
                _loginBw.close();
            }
            _loginBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_LOGIN_MC_LOG + "." + dateString, true), bufferSize);

            if (_registerBw != null){
                _registerBw.close();
            }
            _registerBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_REGISTER_MC_LOG + "."  + dateString, true), bufferSize);

            if (_onlineBw != null){
                _onlineBw.close();
            }
            _onlineBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_ONLINE_MC_LOG + "."  + dateString, true), bufferSize);

            if (_rechargeBw != null){
                _rechargeBw.close();
            }
            _rechargeBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_RECHARGE_MC_LOG + "."  + dateString, true), bufferSize);

            if (_behaviorBw != null){
                _behaviorBw.close();
            }
            _behaviorBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_BEHAVIOR_MC_LOG + "."  + dateString, true), bufferSize);
            
            if (_diamondBw != null){
                _diamondBw.close();
            }
            _diamondBw = new BufferedWriter(new FileWriter(rootPath + pathName + "/cylog/" + Consts.CY_DIAMOND_MC_LOG + "."  + dateString, true), bufferSize);

        } catch (IOException ex) {
            Logger.getLogger(FileLogThreadHandle.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void run() {
        realCurrTime = realPrevTime = realPrevFiveMinutesTime = System.currentTimeMillis();

        // 初始日志文件引用(根据realCurrTime的值)
        setFileRefDaily();
        setFileRefFiveMinuetes();

        try {
            while (!shutdown) {                
                GameLogMessage message = _loginQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _loginBw);
                    message = _loginQueue.poll();
                }

                message = _registerQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _registerBw);
                    message = _registerQueue.poll();
                }

                message = _rechargeQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _rechargeBw);
                    message = _rechargeQueue.poll();
                }

                message = _roleQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _roleBw);
                    message = _roleQueue.poll();
                }

                message = _onlineQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _onlineBw);
                    message = _onlineQueue.poll();
                }

                message = _onlineTimeQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _onlineTimeBw);
                    message = _onlineTimeQueue.poll();
                }

                message = _behaviorQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _behaviorBw);
                    message = _behaviorQueue.poll();
                }

                message = _userQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _userBw);
                    message = _userQueue.poll();
                }

                message = _commodityBuyQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _commodityBuyBw);
                    message = _commodityBuyQueue.poll();
                }

                message = _commodityCostQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _commodityCostBw);
                    message = _commodityCostQueue.poll();
                }

                message = _diamondQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _diamondBw);
                    message = _diamondQueue.poll();
                }

                message = _taskQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _taskBw);
                    message = _taskQueue.poll();
                }

                message = _downloadQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _downloadBw);
                    message = _downloadQueue.poll();
                }

                message = _cardQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _cardBw);
                    message = _cardQueue.poll();
                }

                message = _instanceQueueu.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _instanceBw);
                    message = _instanceQueueu.poll();
                }

                message = _evolutionQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _evolutionBw);
                    message = _evolutionQueue.poll();
                }

                message = _activateQueue.poll();
                while (message != null) {
                    handleFileDebugGameLogMessage((FileCYGameLogMessage) message, _activateBw);
                    message = _activateQueue.poll();
                }
                
                Thread.sleep(100);

                // auto-flush every flush_interval milliseconds
                realCurrTime = System.currentTimeMillis();
                if (realCurrTime - realPrevTime>= flushInterval) {
                    _loginBw.flush();
                    _registerBw.flush();
                    _rechargeBw.flush();
                    _roleBw.flush();
                    _onlineBw.flush();
                    _onlineTimeBw.flush();
                    _behaviorBw.flush();
                    _userBw.flush();
                    _commodityBuyBw.flush();
                    _commodityCostBw.flush();
                    _diamondBw.flush();
                    _taskBw.flush();
                    _downloadBw.flush();
                    _cardBw.flush();
                    _instanceBw.flush();
                    _evolutionBw.flush();
                    _activateBw.flush();

                    // 跨5分钟重建文件
                    if ((realCurrTime + Consts.JET_LAG)/Consts.MILSECOND_1MINITE - (realPrevFiveMinutesTime + Consts.JET_LAG)/Consts.MILSECOND_1MINITE >=5) {
                        realPrevFiveMinutesTime = realCurrTime;
                        setFileRefFiveMinuetes();
                    }
                    // 跨天重建日志文件
                    if ((realCurrTime + Consts.JET_LAG)/Consts.MILSECOND_ONE_DAY > (realPrevTime + Consts.JET_LAG)/Consts.MILSECOND_ONE_DAY) {
                        setFileRefDaily();
                    }
                    realPrevTime = realCurrTime;
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }
    }

    private void handleFileDebugGameLogMessage(FileCYGameLogMessage message, BufferedWriter buffWriter) {
        try {
            List<String> msgList = message.valueList;
            StringBuilder stringBuilder = new StringBuilder(now());
            for (String value : msgList) {
                stringBuilder.append(",").append(value);
            }
            String str = stringBuilder.toString();
            buffWriter.write(str);
            buffWriter.newLine();
        } catch (IOException ex) {
            Logger.getLogger(GameLogger.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
